package mark.tom.fiter;

import android.content.Context;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.io.File;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import mark.tom.fiter.bean.config.RequestConfig;
import mark.tom.fiter.json.BaseJSONArray;
import mark.tom.fiter.json.BaseJSONObject;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.Request;
import okhttp3.RequestBody;

public final class HttpRequestManager {

    private final static String METHOD_GET = "GET";
    private final static String METHOD_POST = "POST";

    public static void initHttpConfig(Buz buz) {
        BuzDispatcher.getInstance().updateBuz(buz);
    }

    /*##########################################################################################################
     *                                           同步请求 Start
     * ##########################################################################################################*/

    /**
     * Description: 发送Get请求(同步)
     * Author: ttmk110@163.com
     * Date: 2021/2/5 10:08
     *
     * @param mUrl           请求地址
     * @param mParam         请求路径参数
     * @param mHeader        请求头参数
     * @param mRequestConfig 请求配置
     * @param <T>            希望获取的数据类型
     * @return 完成解析后的数据
     */
    public static <T> T sendGetRequest(@NonNull String mUrl,
                                       @Nullable Map<String, Object> mParam,
                                       @Nullable Map<String, String> mHeader,
                                       @Nullable RequestConfig mRequestConfig) {
        HttpUrl.Builder newURL = HttpUrl.get(mUrl).newBuilder();
        // 补充Get请求参数
        fixGetRequestParam(newURL, mParam);
        return sendRequest(METHOD_GET, newURL.build(), null, mHeader, mRequestConfig);
    }

    /**
     * Description: 发送Get请求(同步)
     * Author: ttmk110@163.com
     * Date: 2021/2/5 10:08
     *
     * @param mUrl           请求地址
     * @param mParam         请求路径参数
     * @param mHeader        请求头参数
     * @param mRequestConfig 请求配置
     * @param <T>            希望获取的数据类型
     * @return 完成解析后的数据
     */
    public static <T> T sendGetRequest(@NonNull String mUrl,
                                       @Nullable BaseJSONObject mParam,
                                       @Nullable BaseJSONObject mHeader,
                                       @Nullable RequestConfig mRequestConfig) {
        HttpUrl.Builder newURL = HttpUrl.get(mUrl).newBuilder();
        // 补充Get请求参数
        fixGetRequestParam(newURL, mParam);
        return sendRequest(METHOD_GET, newURL.build(), null, mHeader, mRequestConfig);
    }

    /**
     * Description: 发送Post请求(同步)
     * Author: ttmk110@163.com
     * Date: 2021/2/3 16:23
     *
     * @param mUrl           请求地址
     * @param mParam         请求路径参数
     * @param mHeader        请求头参数
     * @param mRequestConfig 请求配置
     * @param <T>            希望获取的数据类型
     * @return 完成解析后的数据
     */
    public static <T> T sendPostRequest(@NonNull String mUrl,
                                        @Nullable BaseJSONObject mParam,
                                        @Nullable BaseJSONObject mHeader,
                                        @Nullable RequestConfig mRequestConfig) {
        HttpUrl.Builder newURL = HttpUrl.get(mUrl).newBuilder();
        return sendRequest(METHOD_POST, newURL.build(), fixPostRequestParam(mParam, mRequestConfig), mHeader, mRequestConfig);
    }

    /**
     * Description: 发送Post请求(同步)
     * Author: ttmk110@163.com
     * Date: 2021/2/3 16:23
     *
     * @param mUrl           请求地址
     * @param mParam         请求路径参数
     * @param mHeader        请求头参数
     * @param mRequestConfig 请求配置
     * @param <T>            希望获取的数据类型
     * @return 完成解析后的数据
     */
    public static <T> T sendPostRequest(@NonNull String mUrl,
                                        @Nullable BaseJSONArray mParam,
                                        @Nullable BaseJSONObject mHeader,
                                        @Nullable RequestConfig mRequestConfig) {
        HttpUrl.Builder newURL = HttpUrl.get(mUrl).newBuilder();
        // 将数据转化为JSON字符串
        RequestBody requestBody =  RequestBody.create(mParam.toString(), MediaType.parse("application/json; charset=utf-8"));
        return sendRequest(METHOD_POST, newURL.build(), requestBody, mHeader, mRequestConfig);
    }

    /*##########################################################################################################
     *                                           同步请求 End
     * ##########################################################################################################*/

    /*##########################################################################################################
     *                                           异步请求 Start
     * ##########################################################################################################*/

    /**
     * Description: 发送Get请求(异步)
     * Author: ttmk110@163.com
     * Date: 2021/2/5 9:02
     *
     * @param mContext         生命周期
     * @param mUrl             请求地址
     * @param mRequestListener 回调事件
     */
    public static void sendGetRequest(@NonNull Context mContext,
                                      @NonNull String mUrl,
                                      @Nullable RequestListener<?> mRequestListener) {
        sendGetRequest(mContext, mUrl, (Map<String, Object>) null, mRequestListener);
    }

    /**
     * Description: 发送Get请求(异步)
     * Author: ttmk110@163.com
     * Date: 2021/2/5 9:02
     *
     * @param mContext         生命周期
     * @param mUrl             请求地址
     * @param mRequestConfig   请求配置
     * @param mRequestListener 回调事件
     */
    public static void sendGetRequest(@NonNull Context mContext,
                                      @NonNull String mUrl,
                                      @Nullable RequestConfig mRequestConfig,
                                      @Nullable RequestListener<?> mRequestListener) {
        sendGetRequest(mContext, mUrl, (Map<String, Object>) null, mRequestConfig, mRequestListener);
    }

    /**
     * Description: 发送Get请求(异步)
     * Author: ttmk110@163.com
     * Date: 2021/2/5 9:02
     *
     * @param mContext         生命周期
     * @param mUrl             请求地址
     * @param mParam           请求路径参数
     * @param mRequestListener 回调事件
     */
    public static void sendGetRequest(@NonNull Context mContext,
                                      @NonNull String mUrl,
                                      @Nullable Map<String, Object> mParam,
                                      @Nullable RequestListener<?> mRequestListener) {
        sendGetRequest(mContext, mUrl, mParam, (Map<String, String>) null, mRequestListener);
    }

    /**
     * Description: 发送Get请求(异步)
     * Author: ttmk110@163.com
     * Date: 2021/2/5 9:02
     *
     * @param mContext         生命周期
     * @param mUrl             请求地址
     * @param mParam           请求路径参数
     * @param mRequestListener 回调事件
     */
    public static void sendGetRequest(@NonNull Context mContext,
                                      @NonNull String mUrl,
                                      @Nullable BaseJSONObject mParam,
                                      @Nullable RequestListener<?> mRequestListener) {
        sendGetRequest(mContext, mUrl, mParam, (BaseJSONObject) null, mRequestListener);
    }

    /**
     * Description: 发送Get请求(异步)
     * Author: ttmk110@163.com
     * Date: 2021/2/5 9:02
     *
     * @param mContext         生命周期
     * @param mUrl             请求地址
     * @param mParam           请求路径参数
     * @param mHeader          请求头参数
     * @param mRequestListener 回调事件
     */
    public static void sendGetRequest(@NonNull Context mContext,
                                      @NonNull String mUrl,
                                      @Nullable Map<String, Object> mParam,
                                      @Nullable Map<String, String> mHeader,
                                      @Nullable RequestListener<?> mRequestListener) {
        sendGetRequest(mContext, mUrl, mParam, mHeader, null, mRequestListener);
    }

    /**
     * Description: 发送Get请求(异步)
     * Author: ttmk110@163.com
     * Date: 2021/2/5 9:02
     *
     * @param mContext         生命周期
     * @param mUrl             请求地址
     * @param mParam           请求路径参数
     * @param mHeader          请求头参数
     * @param mRequestListener 回调事件
     */
    public static void sendGetRequest(@NonNull Context mContext,
                                      @NonNull String mUrl,
                                      @Nullable BaseJSONObject mParam,
                                      @Nullable BaseJSONObject mHeader,
                                      @Nullable RequestListener<?> mRequestListener) {
        sendGetRequest(mContext, mUrl, mParam, mHeader, null, mRequestListener);
    }

    /**
     * Description: 发送Get请求(异步)
     * Author: ttmk110@163.com
     * Date: 2021/2/5 9:02
     *
     * @param mContext         生命周期
     * @param mUrl             请求地址
     * @param mParam           请求路径参数
     * @param mRequestConfig   请求配置
     * @param mRequestListener 回调事件
     */
    public static void sendGetRequest(@NonNull Context mContext,
                                      @NonNull String mUrl,
                                      @Nullable Map<String, Object> mParam,
                                      @Nullable RequestConfig mRequestConfig,
                                      @Nullable RequestListener<?> mRequestListener) {
        sendGetRequest(mContext, mUrl, mParam, (Map<String, String>) null, mRequestConfig, mRequestListener);
    }

    /**
     * Description: 发送Get请求(异步)
     * Author: ttmk110@163.com
     * Date: 2021/2/5 9:02
     *
     * @param mContext         生命周期
     * @param mUrl             请求地址
     * @param mParam           请求路径参数
     * @param mRequestConfig   请求配置
     * @param mRequestListener 回调事件
     */
    public static void sendGetRequest(@NonNull Context mContext,
                                      @NonNull String mUrl,
                                      @Nullable BaseJSONObject mParam,
                                      @Nullable RequestConfig mRequestConfig,
                                      @Nullable RequestListener<?> mRequestListener) {
        sendGetRequest(mContext, mUrl, mParam, (BaseJSONObject) null, mRequestConfig, mRequestListener);
    }

    /**
     * Description: 发送Get请求(异步)
     * Author: ttmk110@163.com
     * Date: 2021/2/5 9:02
     *
     * @param mContext         生命周期
     * @param mUrl             请求地址
     * @param mParam           请求路径参数
     * @param mHeader          请求头参数
     * @param mRequestConfig   请求配置
     * @param mRequestListener 回调事件
     */
    public static void sendGetRequest(@NonNull Context mContext,
                                      @NonNull String mUrl,
                                      @Nullable Map<String, Object> mParam,
                                      @Nullable Map<String, String> mHeader,
                                      @Nullable RequestConfig mRequestConfig,
                                      @Nullable RequestListener<?> mRequestListener) {
        HttpUrl.Builder newURL = HttpUrl.get(mUrl).newBuilder();
        // 补充Get请求参数
        fixGetRequestParam(newURL, mParam);
        // 发送请求
        sendRequest(mContext, METHOD_GET, newURL.build(), null, mHeader, mRequestConfig, mRequestListener);
    }

    /**
     * Description: 发送Get请求(异步)
     * Author: ttmk110@163.com
     * Date: 2021/2/5 9:02
     *
     * @param mContext         生命周期
     * @param mUrl             请求地址
     * @param mParam           请求路径参数
     * @param mHeader          请求头参数
     * @param mRequestConfig   请求配置
     * @param mRequestListener 回调事件
     */
    public static void sendGetRequest(@NonNull Context mContext,
                                      @NonNull String mUrl,
                                      @Nullable BaseJSONObject mParam,
                                      @Nullable BaseJSONObject mHeader,
                                      @Nullable RequestConfig mRequestConfig,
                                      @Nullable RequestListener<?> mRequestListener) {
        HttpUrl.Builder newURL = HttpUrl.get(mUrl).newBuilder();
        // 补充Get请求参数
        fixGetRequestParam(newURL, mParam);
        // 发送请求
        sendRequest(mContext, METHOD_GET, newURL.build(), null, mHeader, mRequestConfig, mRequestListener);
    }

    /**
     * Description: 发送POST请求(异步)
     * Author: ttmk110@163.com
     * Date: 2021/2/3 16:23
     *
     * @param mContext         生命周期
     * @param mUrl             请求地址
     * @param mRequestListener 回调事件
     */
    public static void sendPostRequest(@NonNull Context mContext,
                                       @NonNull String mUrl,
                                       @Nullable RequestListener<?> mRequestListener) {
        sendPostRequest(mContext, mUrl, (BaseJSONObject) null, mRequestListener);
    }

    /**
     * Description: 发送POST请求(异步)
     * Author: ttmk110@163.com
     * Date: 2021/2/3 16:23
     *
     * @param mContext         生命周期
     * @param mUrl             请求地址
     * @param mParam           请求参数
     * @param mRequestListener 回调事件
     */
    public static void sendPostRequest(@NonNull Context mContext,
                                       @NonNull String mUrl,
                                       @Nullable BaseJSONObject mParam,
                                       @Nullable RequestListener<?> mRequestListener) {
        sendPostRequest(mContext, mUrl, mParam, (BaseJSONObject) null, mRequestListener);
    }

    /**
     * Description: 发送POST请求(异步)
     * Author: ttmk110@163.com
     * Date: 2021/2/3 16:23
     *
     * @param mContext         生命周期
     * @param mUrl             请求地址
     * @param mParam           请求参数
     * @param mHeader          请求头参数
     * @param mRequestListener 回调事件
     */
    public static void sendPostRequest(@NonNull Context mContext,
                                       @NonNull String mUrl,
                                       @Nullable BaseJSONObject mParam,
                                       @Nullable BaseJSONObject mHeader,
                                       @Nullable RequestListener<?> mRequestListener) {
        sendPostRequest(mContext, mUrl, mParam, mHeader, null, mRequestListener);
    }

    /**
     * Description: 发送POST请求(异步)
     * Author: ttmk110@163.com
     * Date: 2021/2/3 16:23
     *
     * @param mContext         生命周期
     * @param mUrl             请求地址
     * @param mRequestConfig   请求配置
     * @param mRequestListener 回调事件
     */
    public static void sendPostRequest(@NonNull Context mContext,
                                       @NonNull String mUrl,
                                       @Nullable RequestConfig mRequestConfig,
                                       @Nullable RequestListener<?> mRequestListener) {
        sendPostRequest(mContext, mUrl, null, mRequestConfig, mRequestListener);
    }

    /**
     * Description: 发送POST请求(异步)
     * Author: ttmk110@163.com
     * Date: 2021/2/3 16:23
     *
     * @param mContext         生命周期
     * @param mUrl             请求地址
     * @param mParam           请求参数
     * @param mRequestConfig   请求配置
     * @param mRequestListener 回调事件
     */
    public static void sendPostRequest(@NonNull Context mContext,
                                       @NonNull String mUrl,
                                       @Nullable BaseJSONObject mParam,
                                       @Nullable RequestConfig mRequestConfig,
                                       @Nullable RequestListener<?> mRequestListener) {
        sendPostRequest(mContext, mUrl, mParam, null, mRequestConfig, mRequestListener);
    }

    /**
     * Description: 发送POST请求(异步)
     * Author: ttmk110@163.com
     * Date: 2021/2/3 16:23
     *
     * @param mContext         生命周期
     * @param mUrl             请求地址
     * @param mParam           请求参数
     * @param mHeader          请求头参数
     * @param mRequestConfig   请求配置
     * @param mRequestListener 回调事件
     */
    public static void sendPostRequest(@NonNull Context mContext,
                                       @NonNull String mUrl,
                                       @Nullable BaseJSONObject mParam,
                                       @Nullable BaseJSONObject mHeader,
                                       @Nullable RequestConfig mRequestConfig,
                                       @Nullable RequestListener<?> mRequestListener) {
        HttpUrl.Builder newURL = HttpUrl.get(mUrl).newBuilder();
        // 发送请求
        sendRequest(mContext, METHOD_POST, newURL.build(), fixPostRequestParam(mParam, mRequestConfig), mHeader, mRequestConfig, mRequestListener);
    }

    /**
     * Description: 发送POST请求(异步)
     * Author: ttmk110@163.com
     * Date: 2021/2/3 16:23
     *
     * @param mContext         生命周期
     * @param mUrl             请求地址
     * @param mParam           请求参数
     * @param mHeader          请求头参数
     * @param mRequestConfig   请求配置
     * @param mRequestListener 回调事件
     */
    public static void sendPostRequest(@NonNull Context mContext,
                                       @NonNull String mUrl,
                                       @Nullable BaseJSONArray mParam,
                                       @Nullable BaseJSONObject mHeader,
                                       @Nullable RequestConfig mRequestConfig,
                                       @Nullable RequestListener<?> mRequestListener) {
        HttpUrl.Builder newURL = HttpUrl.get(mUrl).newBuilder();
        // 将数据转化为JSON字符串
        RequestBody requestBody = RequestBody.create(mParam.toString(), MediaType.parse("application/json; charset=utf-8"));;
        // 发送请求
        sendRequest(mContext, METHOD_POST, newURL.build(), requestBody, mHeader, mRequestConfig, mRequestListener);
    }
    /*##########################################################################################################
     *                                           异步请求 End
     * ##########################################################################################################*/

    private static <T> T sendRequest(@NonNull String method,
                                     @NonNull HttpUrl httpUrl,
                                     @Nullable RequestBody requestBody,
                                     @Nullable Map<String, String> mHeader,
                                     @Nullable RequestConfig mRequestConfig) {
        Request.Builder mBuilder = new Request.Builder().url(httpUrl).method(method, requestBody);
        // 补充请求参数
        fixRequestHeader(mBuilder, mHeader);
        // 返回同步请求数据
        return BuzDispatcher.getInstance().executeRequest(mBuilder.build(), mRequestConfig);
    }

    private static <T> T sendRequest(@NonNull String method,
                                     @NonNull HttpUrl httpUrl,
                                     @Nullable RequestBody requestBody,
                                     @Nullable BaseJSONObject mHeader,
                                     @Nullable RequestConfig mRequestConfig) {
        Request.Builder mBuilder = new Request.Builder().url(httpUrl).method(method, requestBody);
        // 补充请求参数
        fixRequestHeader(mBuilder, mHeader);
        // 返回同步请求数据
        return BuzDispatcher.getInstance().executeRequest(mBuilder.build(), mRequestConfig);
    }

    private static void sendRequest(@NonNull Context mContext,
                                    @NonNull String method,
                                    @NonNull HttpUrl httpUrl,
                                    @Nullable RequestBody requestBody,
                                    @Nullable Map<String, String> mHeader,
                                    @Nullable RequestConfig mRequestConfig,
                                    @Nullable RequestListener<?> mRequestListener) {
        Request.Builder mBuilder = new Request.Builder().url(httpUrl).method(method, requestBody);
        // 补充请求参数
        fixRequestHeader(mBuilder, mHeader);
        // 执行请求
        BuzDispatcher.getInstance().executeRequest(mContext, mBuilder.build(), mRequestConfig, mRequestListener);
    }

    private static void sendRequest(@NonNull Context mContext,
                                    @NonNull String method,
                                    @NonNull HttpUrl httpUrl,
                                    @Nullable RequestBody requestBody,
                                    @Nullable BaseJSONObject mHeader,
                                    @Nullable RequestConfig mRequestConfig,
                                    @Nullable RequestListener<?> mRequestListener) {
        Request.Builder mBuilder = new Request.Builder().url(httpUrl).method(method, requestBody);
        // 补充请求参数
        fixRequestHeader(mBuilder, mHeader);
        // 执行请求
        BuzDispatcher.getInstance().executeRequest(mContext, mBuilder.build(), mRequestConfig, mRequestListener);
    }

    private static RequestBody fixPostRequestParam(@Nullable BaseJSONObject mParam,
                                                   @Nullable RequestConfig mRequestConfig) {
        boolean formBody = false, fileBody = false;
        if (null != mRequestConfig) {
            fileBody = mRequestConfig.isRequestFileBody();
            formBody = mRequestConfig.isRequestFormBody();
        }
        RequestBody requestBody;
        if (fileBody) {
            MultipartBody.Builder mBuilder = new MultipartBody.Builder();
            if (null != mParam && mParam.length() > 0) {
                Iterator<String> iterator = mParam.keys();
                while (iterator.hasNext()) {
                    String key = iterator.next();
                    Object value = mParam.opt(key);
                    if (value instanceof File) {
                        File tmp = (File) value;
                        mBuilder.addFormDataPart(key, tmp.getName(), RequestBody.create(tmp, getMediaTypeByFileName(tmp.getName())));
                    } else {
                        mBuilder.addFormDataPart(key, String.valueOf(value));
                    }
                }
            }
            requestBody = mBuilder.build();
        } else if (formBody) {
            // 将数据转化Form表单
            FormBody.Builder mBuilder = new FormBody.Builder();
            if (null != mParam && mParam.length() > 0) {
                Iterator<String> iterator = mParam.keys();
                while (iterator.hasNext()) {
                    String key = iterator.next();
                    String value = String.valueOf(mParam.opt(key));
                    mBuilder.add(key, value);
                }
            }
            requestBody = mBuilder.build();
        } else {
            // 将数据转化为JSON字符串
            requestBody = RequestBody.create(mParam.toString(), MediaType.parse("application/json; charset=utf-8"));
        }
        return requestBody;
    }

    private static MediaType getMediaTypeByFileName(String fileName) {
        String suffix = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
        if ("png".equals(suffix) || "jpg".equals(suffix) || "jpeg".equals(suffix) || "gif".equals(suffix)) {
            return MediaType.parse("image/" + suffix);
        } else {
            return MediaType.parse("text/plain");
        }
    }

    private static void fixGetRequestParam(@NonNull HttpUrl.Builder mBuilder,
                                           @Nullable Map<String, Object> mParam) {
        // 说明需要拼接参数
        if (null == mParam || mParam.size() <= 0) {
            return;
        }
        Set<Map.Entry<String, Object>> entrySet = mParam.entrySet();
        for (Map.Entry<String, Object> entry : entrySet) {
            String key = entry.getKey();
            String value = String.valueOf(entry.getValue());
            mBuilder.addQueryParameter(key, value);
        }
    }

    private static void fixGetRequestParam(@NonNull HttpUrl.Builder mBuilder,
                                           @Nullable BaseJSONObject mParam) {
        // 说明需要拼接参数
        if (null == mParam || mParam.length() <= 0) {
            return;
        }
        Iterator<String> iterator = mParam.keys();
        while (iterator.hasNext()) {
            String key = iterator.next();
            mBuilder.addQueryParameter(key, mParam.optString(key));
        }
    }

    private static void fixRequestHeader(@NonNull Request.Builder mBuilder,
                                         @Nullable Map<String, String> mHeader) {
        if (null == mHeader || mHeader.size() <= 0) {
            return;
        }
        for (Map.Entry<String, String> entry : mHeader.entrySet()) {
            mBuilder.addHeader(entry.getKey(), entry.getValue());
        }
    }

    private static void fixRequestHeader(@NonNull Request.Builder mBuilder,
                                         @Nullable BaseJSONObject mHeader) {
        if (null == mHeader || mHeader.length() <= 0) {
            return;
        }
        Iterator<String> iterator = mHeader.keys();
        while (iterator.hasNext()) {
            String key = iterator.next();
            mBuilder.addHeader(key, mHeader.optString(key));
        }
    }

}
